﻿/*
____
 L|ypps Web controls for ASP.NET

Copyright (c) 2009 Alessandro Zifiglio, http://www.Typps.com
EMail: alessandro@Typps.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
namespace Typps
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Configuration;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Resources;
    using System.Text;
    using System.Web;
    using System.Web.Hosting;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;

    /// <summary>
    /// Summary description for AjaxProgressIndicator
    /// </summary>
    [ToolboxBitmap(typeof(ResourceDummy), "Typps.Resources.Images.updatepanelprogress.bmp")]
    [DesignerAttribute(typeof(Typps.UpdatePanelProgressDesigner))]
    public class UpdatePanelProgress : ControlBase
    {
        #region Fields

        ClientScriptManager cs = null;
        bool _attachToUpdatePanelEventHandlers = true;
        Color _backgroundColor = Color.Black;
        string _cssKey = "Typps.UpdatePanelProgress";
        bool _enableDesignView = true;
        string _keyFormat = "UpdatePanelProgress_{0}";
        HtmlGenericControl _messageContainer;
        string _rootImageSkinFolder = "Typps.Resources.Skins.{0}.Images.UpdatePanelProgress.{1}";
        string _rootSkinFolder = "Typps.Resources.Skins.{0}.{1}";
        string _rootTemplateSkinFolder = "Typps.Resources.Skins.{0}.Templates.{1}";
        string _styleSheetName = "Css.updatepanelprogress.css";

        #endregion Fields

        #region Constructors

        public UpdatePanelProgress()
            : base("div")
        {
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// An image icon displayed in place of textual content for Abort. This will override
        /// AbortRequestButtonText property and will display this image instead. In case you want this
        /// then make sure to provide your own classname to the ButtonCssClass property.
        /// </summary>
        [Editor(typeof(System.Web.UI.Design.ImageUrlEditor), typeof(UITypeEditor)),
        DefaultValue(""),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string AbortButtonIcon
        {
            get
            {
                return (string)(ViewState["AbortButtonIcon"] ?? string.Empty);
            }
            set
            {
                ViewState["AbortButtonIcon"] = value;
            }
        }

        [DefaultValue("Abort"),
        Description("Display text for abort button"),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string AbortRequestButtonText
        {
            get
            {
                return (string)(ViewState["AbortRequestButtonText"] ?? GetLocalizedText("AbortRequestButtonText"));
            }
            set
            {
                ViewState["AbortRequestButtonText"] = value;
            }
        }

        [TypeConverter(typeof(WebColorConverter)),
        DefaultValue(typeof(Color), "black"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public Color BackgroundColor
        {
            get
            {
                if (_backgroundColor == Color.Empty)
                    _backgroundColor = Color.Black;
                return _backgroundColor;
            }
            set
            {
                _backgroundColor = value;
            }
        }

        [DefaultValue("tristatebutton200x33"),
        Description("Css style class name"),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string ButtonCssClass
        {
            get
            {
                return (string)(ViewState["ButtonCssClass"] ?? "tristatebutton200x33");
            }
            set
            {
                ViewState["ButtonCssClass"] = value;
            }
        }

        /// <summary>
        /// An image icon displayed in place of textual content for Cancel. This will override
        /// CancelButtonText property and will display this image instead. In case you want this
        /// then make sure to provide your own classname to the ButtonCssClass property.
        /// </summary>
        [Editor(typeof(System.Web.UI.Design.ImageUrlEditor), typeof(UITypeEditor)),
        DefaultValue(""),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string CancelButtonIcon
        {
            get
            {
                return (string)(ViewState["CancelButtonIcon"] ?? string.Empty);
            }
            set
            {
                ViewState["CancelButtonIcon"] = value;
            }
        }

        [DefaultValue("Cancel"),
        Description("Display text for retry button"),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string CancelButtonText
        {
            get
            {
                return (string)(ViewState["CancelButtonText"] ?? GetLocalizedText("CancelButtonText"));
            }
            set
            {
                ViewState["CancelButtonText"] = value;
            }
        }

        /// <summary>
        /// Sets or retrieves on which side of the object the text will flow
        /// </summary>
        [DefaultValue(typeof(CssFloatStyle), "NotSet"),
        Description("Which side of the object the text will flow."),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public CssFloatStyle CssFloat
        {
            get { return (ViewState["CssFloat"] == null) ? CssFloatStyle.NotSet : (CssFloatStyle)ViewState["CssFloat"]; }
            set { ViewState["CssFloat"] = value; }
        }

        [Editor(typeof(System.Web.UI.Design.ImageUrlEditor), typeof(UITypeEditor)),
        DefaultValue("progressbar.gif"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string ImageUrl
        {
            get
            {
                return (string)(ViewState["ImageUrl"] ?? "progressbar.gif");
            }
            set
            {
                ViewState["ImageUrl"] = value;
            }
        }

        [DefaultValue("Loading..."),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string LoadingMessage
        {
            get
            {
                return (ViewState["LoadingMessage"] == null) ?
                    GetLocalizedText("LoadingMessage") :
                    (string)ViewState["LoadingMessage"];
            }
            set
            {
                ViewState["LoadingMessage"] = value;
            }
        }

        /// <summary>
        /// When true the control will try to resgister the css required by this control.
        /// The default is true. When this control is consumed by the HTML Editor, it's set to
        /// false unless an external stylesheet is referenced by the Embedded instance of this control.
        /// This property is useful for control developers and not for use in user code.
        /// </summary>
        [Browsable(false),
        DefaultValue(true)]
        public virtual bool RegisterCSS
        {
            get
            {
                return (bool)(ViewState["RegisterCSS"] ?? true);
            }
            set
            {
                ViewState["RegisterCSS"] = value;
            }
        }

        /// <summary>
        /// An image icon displayed in place of textual content for Retry. This will override
        /// RetryRequestButtonText property and will display this image instead. In case you want this
        /// then make sure to provide your own classname to the ButtonCssClass property.
        /// </summary>
        [Editor(typeof(System.Web.UI.Design.ImageUrlEditor), typeof(UITypeEditor)),
        DefaultValue(""),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string RetryButtonIcon
        {
            get
            {
                return (string)(ViewState["RetryButtonIcon"] ?? string.Empty);
            }
            set
            {
                ViewState["RetryButtonIcon"] = value;
            }
        }

        [DefaultValue("Retry"),
        Description("Display text for retry button"),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string RetryRequestButtonText
        {
            get
            {
                return (string)(ViewState["RetryRequestButtonText"] ?? GetLocalizedText("RetryRequestButtonText"));
            }
            set
            {
                ViewState["RetryRequestButtonText"] = value;
            }
        }

        [DefaultValue("The request timed out. Want to try again?"),
        Description("Display text for retry button"),
        Category("Appearance"),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public string RetryRequestMessage
        {
            get
            {
                return (string)(ViewState["RetryRequestMessage"] ?? GetLocalizedText("RetryRequestMessage"));
            }
            set
            {
                ViewState["RetryRequestMessage"] = value;
            }
        }

        [DefaultValue(20),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public int Transparency
        {
            get
            {
                return (int)(ViewState["Transparency"] ?? 20);
            }
            set
            {
                ViewState["Transparency"] = value;
            }
        }

        /// <summary>
        /// When this value is true ( the default), the required css is registered in a css inline
        /// whereas to embedding the css directly in the page. In order to make use of
        /// this functionality, you must not edit any of the controls
        /// style properties. Upon editing any of the style properties, the css is
        /// embedded directly in the page output. In this case, your next best option
        /// is to collect the css and manually register an external style sheet yourself.
        /// </summary>
        [DefaultValue(true),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public bool UseCssIncludeOnDefaultState
        {
            get
            {
                return (bool)(ViewState["UseCssIncludeOnDefaultState"] ?? true);
            }
            set
            {
                ViewState["UseCssIncludeOnDefaultState"] = value;
            }
        }

        [DefaultValue(typeof(Unit), ""),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public override Unit Width
        {
            get
            {
                return base.Width;
            }
            set
            {
                base.Width = value;
            }
        }

        [DefaultValue(100000),
        NotifyParentProperty(true),
        RefreshProperties(RefreshProperties.Repaint)]
        public int ZIndex
        {
            get
            {
                return (int)(ViewState["ZIndex"] ?? 100000);
            }
            set
            {
                ViewState["ZIndex"] = value;
            }
        }

        [Browsable(false)]
        internal bool AttachToUpdatePanelEventHandlers
        {
            get
            {
                return _attachToUpdatePanelEventHandlers;
            }
            set
            {
                _attachToUpdatePanelEventHandlers = value;
            }
        }

        internal bool EnableDesignView
        {
            get { return _enableDesignView; }
            set { _enableDesignView = value; }
        }

        protected override string ClassName
        {
            get
            {
                string cn = (this.CssClass != string.Empty) ? this.CssClass : this.ClientID;
                return cn + " updatepanelprogress";
            }
        }

        protected override string CssKey
        {
            get { return _cssKey; }
        }

        protected override string KeyFormat
        {
            get { return _keyFormat; }
        }

        protected override bool RenderSharedStyles
        {
            get { return true; }
        }

        protected override bool RenderTreeViewStyles
        {
            get { return false; }
        }

        protected override string RootImageSkinFolder
        {
            get
            {
                string url = _rootImageSkinFolder;
                if (IsCustomSkin)
                    url = Helper.GetPhysicalPathByResourceNamespace(url, this);
                return url;
            }
        }

        protected override string RootSkinFolder
        {
            get
            {
                string url = _rootSkinFolder;
                if (IsCustomSkin)
                    url = Helper.GetPhysicalPathByResourceNamespace(url, this);
                return url;
            }
        }

        protected override string RootTemplateSkinFolder
        {
            get
            {
                string url = _rootTemplateSkinFolder;
                if (IsCustomSkin)
                    url = Helper.GetPhysicalPathByResourceNamespace(url, this);
                return url;
            }
        }

        protected override string StartupCssStyleIdentifier
        {
            get { return "upp"; }
        }

        protected override string StyleSheetName
        {
            get { return _styleSheetName; }
        }

        #endregion Properties

        #region Methods

        internal virtual void SetAttachUpdatePanelEventHandlerDescriptor(ref ScriptControlDescriptor descriptor)
        {
            descriptor.AddProperty("attachToUpdatePanelEventHandlers", AttachToUpdatePanelEventHandlers);
        }

        internal virtual void SetBackGroundColorDescriptor(ref  ScriptControlDescriptor descriptor)
        {
            descriptor.AddProperty("backgroundColor", ColorTranslator.ToHtml(BackgroundColor));
        }

        internal virtual void SetLoadingMessageDescriptor(ref ScriptControlDescriptor descriptor)
        {
            descriptor.AddProperty("loadingMessage", LoadingMessage);
        }

        internal virtual void SetRetryRequestMessageDescriptor(ref ScriptControlDescriptor descriptor)
        {
            descriptor.AddProperty("retryRequestMessage", RetryRequestMessage);
        }

        internal virtual void SetTransparencyDescriptor(ref  ScriptControlDescriptor descriptor)
        {
            descriptor.AddProperty("transparency", Transparency.ToString());
        }

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            if (!DesignMode || !EnableDesignView)
            {
                writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
                if (CssFloat != CssFloatStyle.NotSet)
                    writer.AddStyleAttribute("float", CssFloat.ToString());
                else if (CssFloat == CssFloatStyle.NotSet && DesignMode)
                    writer.AddStyleAttribute("float", "left");
                this.CssClass = this.ClassName;
            }
            writer.AddStyleAttribute(HtmlTextWriterStyle.ZIndex, ZIndex.ToString());
            base.AddAttributesToRender(writer);
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            if (cs == null && Page != null)
                cs = Page.ClientScript;
            _messageContainer = new HtmlGenericControl("p");
            _messageContainer.ID = "messagecontainer";

            HtmlGenericControl div = new HtmlGenericControl("div");

            Controls.Add(_messageContainer);
            Controls.Add(new LiteralControl("<br />"));

            string abortImageUrl = string.Empty;
            if (!string.IsNullOrEmpty(AbortButtonIcon))
            {
                string defaultAbortButtonIcon = string.Format(
                    RootImageSkinFolder, SelectedSkin, AbortButtonIcon);

                abortImageUrl = Helper.GetBackgroundImageUrl(this,
                    defaultAbortButtonIcon, true, true);
            }
            string retryImageUrl = string.Empty;
            if (!string.IsNullOrEmpty(RetryButtonIcon))
            {
                string defaultRetryButtonIcon = string.Format(
                    RootImageSkinFolder, SelectedSkin, RetryButtonIcon);

                retryImageUrl = Helper.GetBackgroundImageUrl(this,
                    defaultRetryButtonIcon, true, true);
            }
            string cancelImageUrl = string.Empty;
            if (!string.IsNullOrEmpty(cancelImageUrl))
            {
                string defaultCancelButtonIcon = string.Format(
                    RootImageSkinFolder, SelectedSkin, CancelButtonIcon);

                cancelImageUrl = Helper.GetBackgroundImageUrl(this,
                    defaultCancelButtonIcon, true, true);
            }
            HyperLink abortButton = new HyperLink();
            abortButton.ID = "abort";
            abortButton.NavigateUrl = "javascript:void(0);";
            if (!string.IsNullOrEmpty(abortImageUrl))
                abortButton.ImageUrl = abortImageUrl;
            if (!string.IsNullOrEmpty(AbortRequestButtonText))
                abortButton.Text = AbortRequestButtonText;
            abortButton.CssClass = ButtonCssClass;

            HyperLink retryButton = new HyperLink();
            retryButton.ID = "retry";
            retryButton.NavigateUrl = "javascript:void(0);";
            if (!string.IsNullOrEmpty(retryImageUrl))
                retryButton.ImageUrl = retryImageUrl;
            if (!string.IsNullOrEmpty(RetryRequestButtonText))
                retryButton.Text = RetryRequestButtonText;
            retryButton.CssClass = ButtonCssClass;
            retryButton.Style["display"] = "none";

            HyperLink cancelButton = new HyperLink();
            cancelButton.ID = "cancel";
            cancelButton.NavigateUrl = "javascript:void(0);";
            if (!string.IsNullOrEmpty(cancelImageUrl))
                cancelButton.ImageUrl = cancelImageUrl;
            if (!string.IsNullOrEmpty(CancelButtonText))
                cancelButton.Text = CancelButtonText;
            cancelButton.CssClass = ButtonCssClass;
            cancelButton.Style["display"] = "none";

            string progressbarImageUrl = string.Format(
                RootImageSkinFolder, SelectedSkin, ImageUrl);

            string img = "<img id=\"{0}_progressimage\" src=\"{1}\" alt=\"{2}\" />";
            string imgUrl = (ImageUrl.Equals("progressbar.gif")) ?
                Helper.GetBackgroundImageUrl(this, ImageUrl, !DesignMode, true) :
                                ImageUrl;

            img = string.Format(img, ClientID, imgUrl, LoadingMessage);

            Controls.Add(div);

            div.Controls.Add(new LiteralControl(img));
            div.Controls.Add(new LiteralControl("<div style=\"clear:both;\"></div>"));
            HtmlGenericControl buttonContainer = new HtmlGenericControl("div");
            buttonContainer.ID = "buttoncontainer";
            buttonContainer.Style["margin"] = "0 auto 0 auto";
            buttonContainer.Controls.Add(new LiteralControl("<div style=\"clear:both;\"></div>"));

            buttonContainer.Controls.Add(cancelButton);
            buttonContainer.Controls.Add(abortButton);
            buttonContainer.Controls.Add(retryButton);

            div.Controls.Add(buttonContainer);
        }

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor = new ScriptControlDescriptor("Typps.UpdatePanelProgress", ClientID);
            if (DesignMode)
                return new ScriptDescriptor[] { descriptor };
            SetBackGroundColorDescriptor(ref descriptor);
            SetTransparencyDescriptor(ref descriptor);
            SetAttachUpdatePanelEventHandlerDescriptor(ref descriptor);
            SetRetryRequestMessageDescriptor(ref descriptor);
            SetLoadingMessageDescriptor(ref descriptor);
            return new ScriptDescriptor[] { descriptor };
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            if (cs == null) return null;
            bool isDebugMode = SM.ScriptMode == ScriptMode.Debug;
            string script1 = !isDebugMode ? "ClientScripts.startup.min.js" : "ClientScripts.startup.js";
            string script2 = !isDebugMode ? "ClientScripts.updatepanelprogress.min.js" : "ClientScripts.updatepanelprogress.js";
            ScriptReference reference1 = new ScriptReference();
            reference1.Path = cs.GetWebResourceUrl(typeof(ResourceDummy),
                Helper.GetManifestResourceName(script1,
                ManifestResourceNamesCache, isDebugMode));

            ScriptReference reference2 = new ScriptReference();
            reference2.Path = cs.GetWebResourceUrl(typeof(ImagePicker),
                Helper.GetManifestResourceName(script2,
                ManifestResourceNamesCache, isDebugMode));

            return new ScriptReference[] { reference1, reference2 };
        }

        protected override void LoadViewState(object state)
        {
            if (state != null)
            {
                object[] states = (object[])state;
                base.LoadViewState(states[0]);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!this.DesignMode)
                EnsureScriptManager();
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (this.DesignMode) return;
            if (SM == null)
                throw new HttpException("A ScriptManager control must exist on the current page.");

            SM.RegisterScriptControl(this);

            if (RegisterCSS)
                InitializeCSSRegistration();
        }

        protected override string QueryStringData(CssFile cssFileToRegister)
        {
            bool formatStyleSheet = SM.ScriptMode == ScriptMode.Debug;
            StringBuilder queryStrings = new StringBuilder(6);
            queryStrings.AppendFormat("&ctl={0}", (int)ControlName.UpdateProgressPanel);
            queryStrings.AppendFormat("&s={0}", (int)Skin);
            queryStrings.AppendFormat("&cs={0}", CustomSkin);
            queryStrings.AppendFormat("&csf={0}", CustomSkinFolder);
            queryStrings.AppendFormat("&cc={0}", ClassName);
            queryStrings.AppendFormat("&fcss={0}",formatStyleSheet);
            queryStrings.AppendFormat("&cssfile={0}", cssFileToRegister);

            return queryStrings.ToString();
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (base.DesignMode)
            {
                this.EnsureChildControls();
            }
            else
            {
                if (Editor.IsAsyncCallBack) return;
                if (SM != null && SM.SupportsPartialRendering)
                {
                    SM.RegisterScriptDescriptors(this);
                    string disposeComponent = string.Format(@"$find('{0}').dispose();", this.ClientID);
                    //SM.RegisterDispose(this, disposeComponent);
                }
            }
            base.Render(writer);
        }

        protected override void ResetCollectionsAndStyles()
        {
        }

        protected override object SaveViewState()
        {
            object[] states = new object[1];
            states[0] = base.SaveViewState();
            return states;
        }

        protected override void TrackViewState()
        {
            base.TrackViewState();
        }

        #endregion Methods
    }
}